#pragma once
#include "MY_API.hpp"
#include "mysql_module.hpp"
#include "room_manage_module.hpp"
#include <mutex>
#include <list>
#include <string>
#include <condition_variable>
#include <unordered_map>
#include <vector>

template <class T>
class match
{
private:
    // 匹配队列不用队列，是为了删掉指定用户
    std::list<T> _match_queue;
    // 保证线程安全
    std::mutex _mutex;
    // 条件变量，在匹配队列不足两人时，阻塞线程
    std::condition_variable _cond;

public:
    match() {}
    ~match() {}

    // 获取元素个数
    int size()
    {
        std::unique_lock<std::mutex> lock(_mutex);
        return _match_queue.size();
    }

    // 阻塞线程
    void wait()
    {
        std::unique_lock<std::mutex> lock(_mutex);
        _cond.wait(lock);
    }

    // 入队数据，并唤醒线程
    void push(const T &data)
    {
        std::unique_lock<std::mutex> lock(_mutex);
        _match_queue.push_back(data);
        //std::cout << _match_queue.size() << std::endl;
        _cond.notify_all();
    }

    // 出队数据
    bool pop(T &data)
    {
        std::unique_lock<std::mutex> lock(_mutex);
        if (_match_queue.empty() == true)
        {
            return false;
        }
        data = _match_queue.front();
        _match_queue.pop_front();
        return true;
    }

    // 移除指定的数据
    bool remove(T &data)
    {
        std::unique_lock<std::mutex> lock(_mutex);
        _match_queue.remove(data);
        return true;
    }
};

class self_room
{
private:
    // 保证线程安全
    std::mutex _mutex;
    // 条件变量，在遍历所有自创房间不足两人时，阻塞线程
    std::condition_variable _cond;

public:
    // 自己创建房间，后台会收到一个哈希值
    std::unordered_map<std::string, std::vector<int>> _ct_self_room;
    self_room() {}
    ~self_room() {}

    // 获取元素个数
    int size()
    {
        std::unique_lock<std::mutex> lock(_mutex);
        return _ct_self_room.size();
    }

    // 阻塞线程
    void wait()
    {
        std::unique_lock<std::mutex> lock(_mutex);
        _cond.wait(lock);
    }

    // 入队数据，并唤醒线程
    bool push(const std::string &room_num, int uid)
    {
        std::unique_lock<std::mutex> lock(_mutex);
        auto pos = _ct_self_room.find(room_num);
        if (pos == _ct_self_room.end())
        {
            std::vector<int> tmp;
            tmp.push_back(uid);
            //std::cout << "入队了一个房间号，第一个用户的id为 " << uid << std::endl;
            _ct_self_room.insert(std::make_pair(room_num, tmp));
        }
        else if (pos->second.size() <= 2)
        {
            //std::cout << "第二个用户的id为 " << uid << std::endl;
            pos->second.push_back(uid);
        }
        else
        {
            return false;
        }

        _cond.notify_all();
        return true;
    }

    // 出队数据
    bool pop(std::string &room_num, int &uid)
    {
        std::unique_lock<std::mutex> lock(_mutex);
        auto pos = _ct_self_room.find(room_num);
        if (pos == _ct_self_room.end())
        {
            return false;
        }

        uid = pos->second.back();
        pos->second.pop_back();
        if (pos->second.size() <= 0)
        {
            _ct_self_room.erase(pos);
        }

        return true;
    }

    // 移除指定的房间
    bool remove(std::string &room_num)
    {
        std::unique_lock<std::mutex> lock(_mutex);
        auto pos = _ct_self_room.find(room_num);
        if (pos == _ct_self_room.end())
        {
            log_message(ERROR, "该自创房间已经被销毁");
            return false;
        }

        _ct_self_room.erase(pos);
        return true;
    }
};

class match_manage
{
private:
    match<int> _normal;
    match<int> _master;
    self_room _create_room_by_self;
    std::thread _th_normal;
    std::thread _th_master;
    std::thread _th_ct_room;
    room_manage *_rm;
    user_table *_ut;
    online_manage *_om;

private:
    void handle_match(match<int> &match_que)
    {
        while (true)
        {
            while (match_que.size() < 2)
            {
                match_que.wait();
                //std::cout << "匹配线程已被唤醒" << std::endl;
            }

            // std::cout << "创建房间的条件已经满足，线程准备创建房间" << std::endl;
            int uid_1, uid_2;
            if (match_que.pop(uid_1) == false)
            {
                continue;
            }
            if (match_que.pop(uid_2) == false || uid_1 == uid_2)
            {
                add(uid_1);
                continue;
            }

            //std::cout << "两名匹配玩家的uid都获得了分别是" << uid_1 << "  " << uid_2 << std::endl;

            room_ptr rp_1 = _rm->get_room_by_uid(uid_1);
            if (rp_1.get() != nullptr)
            {
                //std::cout << "无法创建房间，用户1还在其它游戏房间中" << std::endl;
                log_message(ERROR, "无法创建房间，用户1还在其它游戏房间中");
                continue;
            }

            room_ptr rp_2 = _rm->get_room_by_uid(uid_2);
            if (rp_2.get() != nullptr)
            {
                //std::cout << "无法创建房间，用户2还在其它游戏房间中" << std::endl;
                log_message(ERROR, "无法创建房间，用户2还在其它游戏房间中");
                continue;
            }

            web_server_t::connection_ptr conn1 = _om->get_connect_from_hall(uid_1);
            if (conn1.get() == nullptr && uid_1 > 0)
            {
                if (uid_2 > 0)
                    add(uid_2);
                continue;
            }

            // std::cout << "uid_1在线  "<< uid_1 << std::endl;

            web_server_t::connection_ptr conn2 = _om->get_connect_from_hall(uid_2);
            if (conn2.get() == nullptr && uid_2 > 0)
            {
                if (uid_1 > 0)
                    add(uid_1);
                continue;
            }

            // std::cout << "uid_2在线  "<< uid_2 << std::endl;

            // std::cout << "开始为匹配成功的玩家创建房间" << std::endl;
            room_ptr tmp = _rm->create_room(uid_1, uid_2);
            if (tmp.get() == nullptr)
            {
                add(uid_1);
                add(uid_2);
                return;
            }

            // 将房间创建成功的信息广播给用户
            Json::Value resp;
            resp["optype"] = "match_success";
            resp["result"] = true;
            std::string body;
            Json_API::serialize(resp, body);

            // std::cout << "匹配成功的玩家创建房间成功" << std::endl;

            if (uid_1 > 0)
                conn1->send(body);
            if (uid_2 > 0)
                conn2->send(body);
        }
    }

    void handle_self_room(self_room &ct_sf_room)
    {
        while (true)
        {
            std::string is_create_room_num;
            while (true)
            {
                bool is_create = false;
                for (auto e : _create_room_by_self._ct_self_room)
                {
                    if (e.second.size() >= 2)
                    {
                        is_create = true;
                        is_create_room_num = e.first;
                        break;
                    }
                }

                if (is_create == true)
                    break;
                ct_sf_room.wait();
                //std::cout << "线程已被唤醒" << std::endl;
            }

            //std::cout << "创建房间的条件已经满足，线程准备创建房间" << std::endl;
            int uid_1, uid_2;
            if (_create_room_by_self.pop(is_create_room_num, uid_1) == false)
            {
                continue;
            }
            if (_create_room_by_self.pop(is_create_room_num, uid_2) == false || uid_1 == uid_2)
            {
                self_add(is_create_room_num, uid_1);
                continue;
            }

            //std::cout << "两名玩家的uid都获得了分别是" << uid_1 << "  " << uid_2 << std::endl;
            web_server_t::connection_ptr conn1 = _om->get_connect_from_hall(uid_1);
            if (conn1.get() == nullptr)
            {
                self_add(is_create_room_num, uid_2);
                continue;
            }

            //std::cout << "uid_1在线  " << uid_1 << std::endl;

            web_server_t::connection_ptr conn2 = _om->get_connect_from_hall(uid_2);
            if (conn2.get() == nullptr)
            {
                self_add(is_create_room_num, uid_1);
                continue;
            }

            //std::cout << "uid_2在线  " << uid_2 << std::endl;

            //std::cout << "开始为开房间的玩家创建房间" << std::endl;
            room_ptr tmp = _rm->create_room(uid_1, uid_2);
            if (tmp.get() == nullptr)
            {
                self_add(is_create_room_num, uid_1);
                self_add(is_create_room_num, uid_2);
                return;
            }

            // 将房间创建成功的信息广播给用户
            Json::Value resp;
            resp["optype"] = "create_success";
            resp["result"] = true;
            resp["room_num"] = is_create_room_num.c_str();
            std::string body;
            Json_API::serialize(resp, body);

            //std::cout << "开房间的玩家创建房间成功" << std::endl;

            conn1->send(body);
            conn2->send(body);
        }
    }

    void enter_normal()
    {
        return handle_match(_normal);
    }

    void enter_master()
    {
        return handle_match(_master);
    }

    void enter_self_room()
    {
        return handle_self_room(_create_room_by_self);
    }

public:
    match_manage(room_manage *rm, user_table *ut, online_manage *om) : _rm(rm), _ut(ut), _om(om), _th_normal(std::thread(&match_manage::enter_normal, this)),
                                                                       _th_master(std::thread(&match_manage::enter_master, this)),
                                                                       _th_ct_room(std::thread(&match_manage::enter_self_room, this)) {}
    int get_normal_queue_size() { return _normal.size(); }
    int get_master_queue_size() { return _master.size(); }

    ~match_manage() {}

    bool add(int uid)
    {
        Json::Value user_msg;
        if (!_ut->select_by_id(uid, user_msg))
        {
            return false;
        }

        // std::cout << "在添加用户到匹配队列中，找到了玩家信息" << std::endl;
        int score = user_msg["score"].asInt();
        if (score < 2000)
        {
            // std::cout << "现在查看玩家是否在房间里" << std::endl;
            if (!_om->is_in_hall(uid))
            {
                return false;
            }
            _normal.push(uid);
            // std::cout << "用户 "<< user_msg["username"].asCString() <<" 添加成功" << std::endl;
            return true;
        }
        else
        {
            if (!_om->is_in_hall(uid))
            {
                return false;
            }
            _master.push(uid);
            // std::cout << "用户 "<< user_msg["username"].asCString() <<" 添加成功" << std::endl;
            return true;
        }
    }

    bool del(int uid)
    {
        Json::Value user_msg;
        if (!_ut->select_by_id(uid, user_msg))
        {
            return false;
        }

        int score = user_msg["score"].asInt();
        if (score < 1000)
        {
            if (!_om->is_in_hall(uid))
            {
                return false;
            }
            _normal.remove(uid);
            return true;
        }
        else
        {
            if (!_om->is_in_hall(uid))
            {
                return false;
            }
            _master.remove(uid);
            return true;
        }
    }

    bool self_add(std::string room_num, int uid)
    {

        // 如果玩家此时已经不在游戏大厅里，则返回错误
        if (!_om->is_in_hall(uid))
        {
            return false;
        }
        bool check = _create_room_by_self.push(room_num, uid);
        if (check == false)
            return false;

        //std::cout << "房间用户：" << uid << " 添加成功" << std::endl;
        return true;
    }

    bool self_del(std::string room_num, int uid)
    {
        if (!_om->is_in_hall(uid))
        {
            return false;
        }
        _create_room_by_self.remove(room_num);
        return true;
    }
};